#include "Socket.h"
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>

using namespace std;
Socket::Socket() {
    fd_ = socket(AF_INET, SOCK_STREAM, 0);
    if (fd_ == -1) {
        perror("socket");
        exit(1);
    }
}

bool Socket::Listen() {
    int r = listen(fd_, 128);
    if (r == -1) {
        perror("listen");
        return false;
    }
    return true;
}
bool Socket::Bind(const std::string& ip, const unsigned short port) {
    this->ip_ = ip;
    this->port_ = port;
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    inet_pton(AF_INET, ip.c_str(), &addr.sin_addr.s_addr);
    socklen_t len = sizeof(addr);
    if (::bind(fd_, (sockaddr*)&addr, len) == -1) {
        perror("bind");
        exit(1);
        return false;
    }
    return true;
}
void Socket::initAddr(const std::string& ip, const unsigned short port) {
    this->ip_ = ip;
    this->port_ = port;
}
Socket* Socket::Accept(SockAddrIn* addr) {
    // auto addr = addr->getAddr();
    sockaddr_in addrin{0};
    socklen_t len = sizeof(addrin);
    int cfd = accept(fd_, (sockaddr*)&addrin, &len);
    if (cfd == -1) {
        perror("accept");
        return nullptr;
    }
    char ip[24]{0};
    inet_ntop(AF_INET, &addrin.sin_addr.s_addr, ip, 24);
    int port =  ntohs(addrin.sin_port); 
    auto cs = new Socket{cfd};
    cs->initAddr(ip, port);
    return cs;
}
void Socket::setNonBlock() {
    int flags = fcntl(fd_, F_GETFL, 0);
    fcntl(fd_, F_SETFL, flags | O_NONBLOCK);
}
void Socket::setReusable() {
    int opt = 1;
    setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}
ostream& Socket::showInfo() {
    return cout << "ip: " << ip_ << " port: " << port_ << " ";
}
Socket::~Socket() {
    if (fd_ == -1) return;
    close(fd_);
}
